package com.efrei.schoolmanager.controlers;

import java.util.List;
import java.util.Set;

import com.efrei.schoolmanager.exceptions.LogicException;
import com.efrei.schoolmanager.model.hibernate.dao.ClasseDAO;
import com.efrei.schoolmanager.model.obj.Classe;
import com.efrei.schoolmanager.model.obj.Eleve;
import com.efrei.schoolmanager.model.obj.Matiere;
import com.efrei.schoolmanager.model.obj.Note;

/**
 * controleur pour la gestion des note poiur une classe :
 * <ul>
 * <li>la récupération de la liste des notes pour une classe</li>
 * <li>l'ajout</li>
 * <li>la suppression</li>
 * </ul>
 * 
 * @author pierrick
 */
public class ControleurNote extends ControleurTransactionnel {

	// dao
	// private NoteDAO noteDAO;
	private final ClasseDAO classeDao;
	// données
	private List<Classe> classes;

	private Classe classeCourante;
	private Matiere matiereCourante;

	public ControleurNote() throws LogicException {
		// instanciations
		// noteDAO = new NoteDAO(getSession());
		classeDao = new ClasseDAO(getSession());
		// requete de la classe
		try {
			this.classes = classeDao.getClasses();
		} catch (Exception e) {
			e.printStackTrace();
			throw new LogicException("classes non recupérés");
		}
	}

	/**
	 * @return les notes pour la classe courante. Il faudra trier selon la
	 *         matiere courante
	 */
	public Set<Note> getNotes() {
		return classeCourante.getNotes();
	}

	/**
	 * ajoute une nouvelle note avec les infos données
	 * 
	 * @param eleve
	 * @param matiere
	 * @param periode
	 * @param numControle
	 * @param note
	 */
	public void addNote(Eleve eleve, int periode, int numControle, float note) {
		Note newNote = new Note(eleve, classeCourante, matiereCourante,
				periode, numControle, note);
		// ajout a la liste
		classeCourante.getNotes().add(newNote);
	}

	/**
	 * edite la note existante avec les données fournis en parametres
	 * 
	 * @param note
	 * @param eleve
	 * @param matiere
	 * @param periode
	 * @param numControle
	 * @param note
	 * @throws LogicException
	 */
	public void updateNote(Note note, float noteValue) throws LogicException {
		// si note non connu
		if (!classeCourante.getNotes().contains(note)) {
			throw new LogicException("Note non connu");
		}
		note.setNote(noteValue);
	}

	/**
	 * supprime pour toutes les notes celles qui ont le numControle donné en
	 * argument
	 * 
	 * @param numControle
	 *            a supprimer
	 * @throws LogicException
	 */
	public void deleteNoteByNumControle(int periode, int numControle)
			throws LogicException {
		if (classeCourante == null || matiereCourante == null) {
			throw new LogicException(
					"destruction de notes impossible si aucune matiere courante");
		}
		for (Note note : getNotes()) {
			// si même periode/numControle mais aussi pour classeCourante et
			// matiereCourante
			if (note.getNumControle() == numControle
					&& note.getPeriode() == periode
					&& note.getClasse() == classeCourante
					&& note.getMatiere() == matiereCourante) {
				removeNote(note);
			}
		}
	}

	/**
	 * supprime de la liste et donc de la base la note donnée en argument
	 * 
	 * @param note
	 */
	public void removeNote(Note note) {
		classeCourante.getNotes().remove(note);
	}

	@Override
	public void validAndQuit() throws LogicException {
		// on sauvegarde les classes (et donc les notes) avant de quitter
		for (Classe classe : classes) {
			classeDao.update(classe);
		}
		super.validAndQuit();
	}

	public List<Classe> getClasses() {
		return classes;
	}

	/**
	 * demande la liste des matieres et definie classe comme nouvelle classe
	 * courante
	 * 
	 * @param classe
	 * @return
	 */
	public Set<Matiere> getMatieres(Classe classe) {
		setClasseCourante(classe);
		return classe.getMatieres();
	}

	/**
	 * @return la classe courante
	 */
	public Classe getClasseCourante() {
		return classeCourante;
	}

	/**
	 * affecte classe courante (aussi effectué avec {@link #getMatieres(Classe)}
	 * )
	 * 
	 * @param classeCourante
	 *            null pour desactiver classe courante
	 */
	public void setClasseCourante(Classe classeCourante) {
		this.classeCourante = classeCourante;
	}

	/**
	 * @see #setMatiereCourante(Matiere)
	 */
	public Matiere getMatiereCourante() {
		return matiereCourante;
	}

	/**
	 * @param matiere
	 *            devient la nouvelle matiere courante
	 */
	public void setMatiereCourante(Matiere matiere) {
		this.matiereCourante = matiere;
	}
}
